using MiniExcelLibs;

namespace Beauty.Net.MiniExcel.Core;

/// <summary>
/// MiniExcel服务实现
/// </summary>
public class MiniExcelService : IMiniExcelService, IDisposable
{

    private bool _disposed = false;

    public MiniExcelService()
    {
        Dispose(false);
    }

    /// <summary>
    /// 导出数据到Excel文件
    /// </summary>
    public void ExportToFile<T>(IEnumerable<T> data, string filePath, string sheetName = "Sheet1") where T : class, new()
    {
        if (data == null)
            throw new ArgumentNullException(nameof(data));
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));
        if (string.IsNullOrWhiteSpace(sheetName))
            throw new ArgumentNullException(nameof(sheetName));

        try
        {
            // 确保目录存在
            var directory = Path.GetDirectoryName(filePath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            MiniExcelLibs.MiniExcel.SaveAs(filePath, data, sheetName: sheetName, excelType: ExcelType.XLSX);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"导出Excel文件失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 导出数据到Excel流
    /// </summary>
    public MemoryStream ExportToStream<T>(IEnumerable<T> data, string sheetName = "Sheet1") where T : class, new()
    {
        if (data == null)
            throw new ArgumentNullException(nameof(data));
        if (string.IsNullOrWhiteSpace(sheetName))
            throw new ArgumentNullException(nameof(sheetName));

        var memoryStream = new MemoryStream();
        try
        {
            MiniExcelLibs.MiniExcel.SaveAs(memoryStream, data, sheetName: sheetName, excelType: ExcelType.XLSX);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return memoryStream;
        }
        catch
        {
            memoryStream?.Dispose();
            throw;
        }
    }

    /// <summary>
    /// 从Excel文件导入数据
    /// </summary>
    public List<T> ImportFromFile<T>(string filePath, string? sheetName = null, string startCell = "A1") where T : class, new()
    {
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));
        if (!File.Exists(filePath))
            throw new FileNotFoundException($"文件不存在: {filePath}");

        try
        {
            return MiniExcelLibs.MiniExcel.Query<T>(filePath, sheetName: sheetName, startCell: startCell).ToList();
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"从Excel文件导入数据失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 从Excel流导入数据
    /// </summary>
    public List<T> ImportFromStream<T>(Stream stream, string? sheetName = null, string startCell = "A1") where T : class, new()
    {
        if (stream == null)
            throw new ArgumentNullException(nameof(stream));
        if (!stream.CanRead)
            throw new InvalidOperationException("流不可读");

        var position = stream.Position;
        try
        {
            stream.Seek(0, SeekOrigin.Begin);
            return MiniExcelLibs.MiniExcel.Query<T>(stream, sheetName: sheetName, startCell: startCell, excelType: ExcelType.XLSX).ToList();
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"从Excel流导入数据失败: {ex.Message}", ex);
        }
        finally
        {
            stream.Position = position;
        }
    }

    /// <summary>
    /// 异步导出数据到Excel文件
    /// </summary>
    public async Task<List<T>> ImportFromFileAsync<T>(string filePath, string? sheetName = null, string startCell = "A1", CancellationToken cancellationToken = default) where T : class, new()
    {
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));
        if (!File.Exists(filePath))
            throw new FileNotFoundException($"文件不存在: {filePath}");

        try
        {
            var queryResult = await MiniExcelLibs.MiniExcel.QueryAsync<T>(filePath, sheetName: sheetName, startCell: startCell, cancellationToken: cancellationToken);
            return queryResult.ToList();
        }
        catch (OperationCanceledException)
        {
            throw;
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"异步从Excel文件导入数据失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 使用模板导出数据（MiniExcel的重要特性）[2,6](@ref)
    /// </summary>
    public void ExportByTemplate<T>(string templatePath, string outputPath, T data, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrWhiteSpace(templatePath))
            throw new ArgumentNullException(nameof(templatePath));
        if (string.IsNullOrWhiteSpace(outputPath))
            throw new ArgumentNullException(nameof(outputPath));
        if (data == null)
            throw new ArgumentNullException(nameof(data));
        if (!File.Exists(templatePath))
            throw new FileNotFoundException($"模板文件不存在: {templatePath}");

        try
        {
            // 确保输出目录存在
            var directory = Path.GetDirectoryName(outputPath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            MiniExcelLibs.MiniExcel.SaveAsByTemplate(outputPath, templatePath, data);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"模板导出失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 使用IDataReader导出大数据量（推荐用于大数据量场景）[2,3](@ref)
    /// </summary>
    public void ExportWithDataReader(System.Data.IDataReader dataReader, string filePath, string sheetName = "Sheet1")
    {
        if (dataReader == null)
            throw new ArgumentNullException(nameof(dataReader));
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));

        try
        {
            // 确保目录存在
            var directory = Path.GetDirectoryName(filePath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            MiniExcelLibs.MiniExcel.SaveAs(filePath, dataReader, sheetName: sheetName, excelType: ExcelType.XLSX);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"使用DataReader导出失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 获取Excel工作表名称列表
    /// </summary>
    public IList<string> GetSheetNames(string filePath)
    {
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));
        if (!File.Exists(filePath))
            throw new FileNotFoundException($"文件不存在: {filePath}");

        try
        {
            return MiniExcelLibs.MiniExcel.GetSheetNames(filePath).ToList();
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"获取工作表名称失败: {ex.Message}", ex);
        }
    }

    /// <summary>
    /// 验证Excel文件格式
    /// </summary>
    public bool ValidateExcelFormat(string filePath)
    {
        if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
            return false;

        try
        {
            var extension = Path.GetExtension(filePath).ToLowerInvariant();
            return extension == ".xlsx" || extension == ".xls";
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // 释放托管资源
            }
            _disposed = true;
        }
    }

    public async Task ExportToFileAsync<T>(IEnumerable<T> data, string filePath, string sheetName = "Sheet1", CancellationToken cancellationToken = default) where T : class, new()
    {
        if (data == null)
            throw new ArgumentNullException(nameof(data));
        if (string.IsNullOrWhiteSpace(filePath))
            throw new ArgumentNullException(nameof(filePath));
        if (string.IsNullOrWhiteSpace(sheetName))
            throw new ArgumentNullException(nameof(sheetName));

        try
        {
            // 确保目录存在
            var directory = Path.GetDirectoryName(filePath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            await MiniExcelLibs.MiniExcel.SaveAsAsync(filePath, data, sheetName: sheetName, excelType: ExcelType.XLSX, cancellationToken: cancellationToken);
        }
        catch (OperationCanceledException)
        {
            throw;
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"异步导出Excel文件失败: {ex.Message}", ex);
        }
    }

}

